package rkw.communication;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import core.communication.message.CommunicationTestMessage;
import core.communication.message.Message;
import core.communication.message.NodeStateEnum;

@Component
@Scope("prototype")
public class ClientChecker implements ApplicationContextAware, Runnable {

	private static final Logger L = LoggerFactory.getLogger(ClientChecker.class);

	private ApplicationContext context;

	private volatile Thread thread = null;
	private Message message;
	private CommunicationService communicationService;

	public ClientChecker() {
		L.debug("Tworzę ClientChecker");

		message = new CommunicationTestMessage();
		thread = new Thread(this, "checker");

		L.debug("Utworzono ClientChecker");
	}

	public void stop() {
		L.debug("Stop: {} {}", thread.getName(), thread.getId());

		thread = null;
		wakeUp();
	}

	public synchronized void wakeUp() {
		L.debug("Wstaje: ClientChecker");

		notify();
	}

	@Override
	public void run() {
		communicationService = context.getBean(CommunicationService.class);
		Client client = null;
		while (thread != null) {
			client = null;
			L.debug("Pobieram klienta do sprawdzenia");
			client = communicationService.getClientToCheck();
			if (client == null) {
				synchronized (this) {
					try {
						if (thread == null)
							return;
						L.debug("Nie ma klienta do sprawdzenia, usypiam");
						wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			} else {
				message.setDestinationURI(client.getLocatorURI());
				try {
					client.send(message);
					if (thread == null)
						return;
					client.setIsWorking(true);
					communicationService.removeClientToCheck(client);
					communicationService.sendNodeStateMessage(message.getDestinationURI(), NodeStateEnum.ON);
				} catch (Throwable e) {
					communicationService.reAddClientToCheck(client);
					if (thread == null)
						return;
				}
			}
		}
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.context = applicationContext;
	}
}
